package com.bckj.fastboot;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.google.auto.service.AutoService;

import javax.annotation.processing.*;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;
import javax.tools.JavaFileObject;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

@AutoService(Processor.class)
@SupportedAnnotationTypes({"com.baomidou.mybatisplus.annotation.TableName"})
public class MyBatisProcessor extends AbstractProcessor {
    private Elements elementUtils;
    private Filer filer;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        this.elementUtils = processingEnv.getElementUtils();
        this.filer = processingEnv.getFiler();
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        // 1. 收集所有被@Entity注解的类
        Set<? extends Element> entities = roundEnv.getElementsAnnotatedWith(TableName.class);
        // 2. 为每个实体生成字段常量类
        for (Element entity : entities) {
            try {
                generateColumnsClass((TypeElement) entity);
            } catch (IOException e) {
                System.err.println("生成字段类失败: " + e.getMessage());
            }
        }
        return true;
    }

    private void generateColumnsClass(TypeElement entity) throws IOException {
        String className = entity.getSimpleName().toString();
        String packageName = entity.getEnclosingElement().toString();
        TableName entityAnno = entity.getAnnotation(TableName.class);
        String tableName = entityAnno.value() == null || entityAnno.value().isEmpty() ? entity.getSimpleName().toString() : entityAnno.value();
        // 2.1 创建源文件
        JavaFileObject file = filer.createSourceFile(
                packageName + ".generated." + toUpperSnakeCase(className));

        // 2.2 收集字段信息
        List<ColumnInfo> columns = new ArrayList<>();
        for (Element field : elementUtils.getAllMembers(entity)) {
            TableId idAnno = field.getAnnotation(TableId.class);
            TableField columnAnno = field.getAnnotation(TableField.class);

            if (idAnno != null) {
                String columnName = idAnno.value().isEmpty() ?
                        camelToSnake(field.getSimpleName().toString()) : idAnno.value();
                columns.add(new ColumnInfo().setFieldName(field.getSimpleName().toString()).setColumnName(columnName));
            } else if (columnAnno != null) {
                if (columnAnno.exist()) {
                    String columnName = columnAnno.value().isEmpty() ?
                            camelToSnake(field.getSimpleName().toString()) : columnAnno.value();
                    columns.add(new ColumnInfo().setFieldName(field.getSimpleName().toString()).setColumnName(columnName));
                }
            }
        }


        // 2.3 生成Java代码
        try (PrintWriter out = new PrintWriter(file.openWriter())) {
            // 包声明
            out.printf("""
                    package %s;
                    
                    import com.bckj.fastboot.core.sql.meta.Column;
                    import com.bckj.fastboot.core.sql.meta.FixedColumn;
                    import com.bckj.fastboot.core.sql.meta.Table;
                    import com.bckj.fastboot.core.sql.meta.TableLike;
                    
                    import java.util.Collection;
                    import java.util.List;
                    
                    """.formatted(packageName + ".generated"));

            // 类注释
            out.println("""
                    /**
                     * 自动生成的字段常量类
                     * 对应表: %s.%s
                     */
                    """.formatted(entityAnno.schema(), entityAnno.value()));
            String newClassName = toUpperSnakeCase(className);
            // 表相关
            out.println("""
                    public final class %s implements TableLike {
                    
                       private final String alias;
                    
                       /** 数据库表名 */
                       public static final String TABLE_NAME = "%s";
                    
                       public static final %s SELF = new %s(null);
                    
                       public static %s alias(String alias) {
                            var table = new %s(alias);
                            return table;
                       }
                    
                       private %s(String alias) {
                            this.alias = alias;
                       }
               
                       @Override
                       public String getTableName() {
                           return TABLE_NAME;
                       }
                   
                       @Override
                       public Collection<Column> getColumns() {
                           return COLUMNS;
                       }
                    
                       @Override
                       public String getAlias() {
                           return this.alias;
                       }
                    
                    """.formatted(newClassName, tableName,
                    newClassName, newClassName, newClassName, newClassName, newClassName));

            List<String> newFieldNames = new ArrayList<>();
            // 字段相关
            for (ColumnInfo column : columns) {
                String newFieldName = toUpperSnakeCase(column.getColumnName());
                out.println("""
                            public static final FixedColumn %s = new FixedColumn(SELF, "%s");
                        
                            public Column %s() {
                                return new Column(this, "%s", null);
                            }
               
                        """.formatted(newFieldName, column.getColumnName(), column.getColumnName(), column.getColumnName()));
                newFieldNames.add(newFieldName);
            }

            out.println("""
                       public static List<Column> COLUMNS = List.of(%s);
                    }
                    """.formatted(String.join(",", newFieldNames)));
        }
    }

    public static String camelToSnake(String str) {
        // 处理空值
        if (str == null || str.isEmpty()) {
            return str;
        }

        // 正则替换：在大写字母前添加下划线，然后转小写
        return str.replaceAll("([A-Z])", "_$1")
                .toLowerCase()
                // 处理首字母可能被加下划线的情况
                .replaceAll("^_", "");
    }

    public static String toUpperSnakeCase(String input) {
        if (input == null || input.isEmpty()) {
            return input;
        }

        // 处理大小驼峰转下划线

        return input.replaceAll("([a-z])([A-Z])", "$1_$2")
                .replaceAll("([A-Z])([A-Z][a-z])", "$1_$2")
                .toUpperCase();
    }
}